package com.sojoys.artifact.third.web.router;

import java.net.URL;

import com.sojoys.artifact.constant.ArtifactErrorCode;
import com.sojoys.artifact.core.IRouter;
import com.sojoys.artifact.exception.AbstractLogicModelException;
import com.sojoys.artifact.manager.JsonManager;
import com.sojoys.artifact.third.web.core.NettyHttpContext;
import com.sojoys.artifact.tools.RenderBean;

import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;

/**
 * 路由中心<br/>
 * 请求拦截器<br/>
 * 静态文件路由<br/>
 * CiHandler脚本路由<br/>
 * 
 * @author zhh
 */
public class CiRouter implements IRouter {

	private static InternalLogger logger = InternalLoggerFactory.getInstance(CiRouter.class);

	private FileRouter file;
	// 脚本-动态添加类
	private CiScaner scaner;
	// 拦截器
	private IRouter filter;

	public CiRouter() {
		file = new FileRouter("www");
		scaner = new CiScaner();
	}

	/**
	 * 设置静态文件路由
	 * 
	 * @param dir
	 *            磁盘文件目录
	 * @param path
	 *            http请求路由路径
	 * @param maxAge
	 *            静态文件缓存时间(秒)
	 * @param exceptExtend
	 *            排除的文件后缀
	 */
	public void setFile(String dir, String path, int maxAge, String exceptExtend) {
		if (dir.isEmpty() && path.isEmpty()) {
			return;
		}
		file = new FileRouter(dir, path, maxAge, exceptExtend);
	}

	/**
	 * 设置静态文件路由
	 * 
	 * @param f
	 */
	public void setFile(FileRouter f) {
		if (f != null) {
			file = f;
		}
	}

	/**
	 * 获取静态文件路由
	 * 
	 * @return
	 */
	public FileRouter getFile() {
		return file;
	}

	/**
	 * 获取filter
	 * 
	 * @return
	 */
	public IRouter getFilter() {
		return filter;
	}

	/**
	 * 设置filter
	 * 
	 * @param r
	 */
	public void setFilter(IRouter r) {
		filter = r;
	}

	/**
	 * 设置脚本扫描器
	 * 
	 * @param dir
	 *            扫描路径
	 * @param packageName
	 *            扫描限定包
	 */
	public void setHandler(String dir, String packageName) {
		scaner = new CiScaner(dir, packageName, scaner.handlers());
	}

	/**
	 * 获取脚本扫描器
	 * 
	 * @return
	 */
	public CiScaner getHandler() {
		return scaner;
	}

	/**
	 * 直接添加脚本实现类
	 * 
	 * @param clazz
	 */
	public void add(Class<?> clazz) {
		scaner.add(clazz);
	}

	/**
	 * call
	 * 
	 * @param ctx
	 * @return
	 * @throws Exception
	 */
	public boolean call(NettyHttpContext ctx) throws Exception {
		try {
			// 拦截器
			if (filter != null && filter.call(ctx)) {
				return true;
			}
			// 文件处理器
			if (file != null && file.match(ctx)) {
				return file.call(ctx);
			}
			// Controller
			CiHandler wrap = scaner.get(ctx);
			if (wrap != null) {
				return wrap.call(ctx);
			}
		} catch (Exception e) {
			if (e.getCause() instanceof AbstractLogicModelException) {
				AbstractLogicModelException abstractLogicModelException = (AbstractLogicModelException) e.getCause();
				RenderBean renderBean = new RenderBean();
				renderBean.setStatus(abstractLogicModelException.getCode());
				renderBean.setDescription(abstractLogicModelException.getMessage());
				ctx.send(JsonManager.me().getJson().toJson(renderBean));
			} else {
				ctx.out().setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR);
				// logger.error("call", e);
				StackTraceElement[] arr = e.getCause().getStackTrace();
				StringBuilder sb = new StringBuilder();
				for (StackTraceElement s : arr) {
					// sun.reflect.NativeMethodAccessorImpl
					if (s.getClassName().startsWith("sun.")) {
						break;
					}
					sb.append(s).append('\n');
				}
				logger.error(sb.toString());
				RenderBean renderBean = new RenderBean();
				renderBean.setStatus(ArtifactErrorCode.UNKNOWN_ERROR);
				renderBean.setDescription("服务器异常");
				ctx.out().setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR);
				ctx.send(JsonManager.me().getJson().toJson(renderBean));
			}
			return true;
		}
		return false;
	}

	/**
	 * 脚本扫描路径URL
	 * 
	 * @return
	 */
	public URL[] urls() {
		return scaner.urls();
	}

	/**
	 * 重新扫描脚本
	 */
	public synchronized void reload() {
		this.scaner = new CiScaner(scaner.dir(), scaner.packageName(), scaner.handlers());
	}

}
